/**
 * 实现方法流程定制化
 * @author hushaoli
 */

/**
 * 引入后台打印日志控件
 */
import myLog from "./../../components/log/log.js";

/**
 * 流程map
 * key: 不同流程的名字
 * value: 具体流程的实例（包括流程的执行方法和执行过程)
 */
var process_map = new Map();

/**
 * 流程过滤器map
 * key : 不同过滤器名称
 * value : 具体流程过滤器方法(用于筛选对应的流程)
 */
var filter_map = new Map();

/**
 * 增加一个新的流程
 * @param key : 流程名称
 * @return : 具体流程的实例（包括流程的执行方法和执行过程)
 */
function addProcess(key) {
    var preProcess = process_map.get(key);
    if (typeof preProcess == undefined || preProcess == undefined) {
        var tmp = this.create(key);
        process_map.set(key, tmp);
        return tmp;
    } else {
        return preProcess;
    }
}


/**
 * 流程选择器
 * @params filterFun : 选择器方法（通过选择器来选择对应的流程，返回结果为流程的名称）
 * @params params : 选择器方法的输入参数（可为空)
 */
function addFilter(key, filterFun, res) {
    var filterHandle = filter_map.get(key);
    if (typeof filterHandle == undefined || filterHandle == undefined) {
        filterHandle = {
            fHandle: filterFun,
            params: res,
            getProcess: function() {
                var returnKey = this.fHandle(this.params);
                return getProcess(returnKey);
            }
        };
        filter_map.set(key, filterHandle);
        return filterHandle;
    } else {

        return filterHandle;
    }
}

function getFilter(key) {
    return filter_map.get(key);
}

/**
 * 获取一个已有的流程
 * @param key : 流程名称
 * @return : 具体流程的实例（包括流程的执行方法和执行过程)
 */
function getProcess(key) {
    return process_map.get(key);
}

/**
 * 创建一个流程实例
 * @return 返回流程实例
 */
function create(process_name) {
    var process_info = {
        process_name: process_name,
        errDefault: undefined,
        timeFunction: undefined,
        sysTimeoutFunc: undefined, //解决在执行一个节点函数时，该节点由于等待监听回调而无法进行下一步操作的BUG
        finalFunction: undefined,
        timeout: 0,
        timeBegin: new Date(),
        processList: {}, //主流程函数存储结构
        processNameList: {}, //主流程函数名称存储结果（用于开发模式下的日志打印）
        errList: {}, //每个方法的错误函数
        preList: {}, //每个方法的预处理函数
        afterList: {}, //每个方法的后处理函数
        rejectList: {}, //每个方法对应的拒绝处理逻辑（调用该方法，触发拒绝逻辑，并终止流程)
        current_index: 0, //当前处理的函数位置
        size: 0, //当前流程方法个数
        isRunning: true, //运行状态  (废弃，使用缓存来保持运行状态)
        isRunningKey: process_name + "_isRunning",
        redirectTo_url: undefined, //跳转地址
        redirectTo_type: undefined, //跳转方式
        env: "pro", //开发模式(pro: 线上模式; dev:开发模式[默认为pro模式])
        process_start_data: undefined,

        /**
         * 打印日志函数
         * @param {日志消息} msg 
         */
        log(msg) {
            myLog.log(this.process_name, msg);
        },
        /**
         * 设置为开发模式
         * 用于开发模式，打印每个节点的输入参数和输出参数
         */
        dev() {
            myLog.dev(this.process_name);
            return this;
        },
        /**
         * 增加流程方法
         */
        add: function(curr, curr_name) {
            this.processList[this.size] = curr;
            if (typeof curr_name == undefined || curr_name == undefined) {
                this.processNameList[this.size] = "Function_" + this.size;
            } else {
                this.processNameList[this.size] = curr_name;
            }
            this.size++;
            return this;
        },
        /**
         * 增加流程方法
         */
        add_err: function(errFunction) {
            this.errList[this.size] = errFunction;
            return this;
        },
        add_err_default: function(errFunction) {
            this.errDefault = errFunction;
            return this;
        },
        /**
         * 增加流程预处理方法
         */
        add_pre: function(preFunction) {
            this.preList[this.size - 1] = preFunction;
            return this;
        },
        /**
         * 增加流程后处理方法
         */
        add_after: function(afterFunction) {
            this.afterList[this.size - 1] = afterFunction;
            return this;
        },
        add_reject: function(rejectFunction) {
            this.rejectList[this.size - 1] = rejectFunction;
            return this;
        },
        /**
         * 判断当前流程是否在执行
         * @return isRunning : true-在运行中， false：未运行
         */
        get_state: function() {
            return this.isRunning;
        },
        set_state: function(state) {
            this.isRunning = state;
        },
        /**
         * 当前执行到哪一步
         */
        get_current_index: function() {
            return this.current_index;
        },
        /**
         * @param {最后的执行方法} fun 
         */
        finally: function(finalFun) {
            this.finalFunction = finalFun;
            return this;
        },
        /**
         * 重新走流程，但是定时器重置 
         */
        run_again(res) {
            /**
             * 初始化入参
             */
            if (typeof res == undefined || res == undefined) {
                res = this.process_start_data;
            }
            /**
             * 清理数据
             */
            this.finalize();
            /**
             * 初始化启动参数
             */
            this.current_index = 1;
            this.set_state(true);
            this.sysTimeoutFunc = undefined;

            //开发模式下的日志打印
            if (typeof res != undefined && res != undefined) {
                this.log("return data is ---------");
                this.log(res);
            }
            this.log("------rerun the process-------");
            this.log("开始调用方法:" + this.processNameList[this.current_index - 1]);
            try {
                /**
                 * 判断是否需要预处理
                 */
                var pre_res = this.preList[this.current_index - 1];
                if (typeof pre_res != undefined && pre_res) {
                    res = pre_res(res);
                }
                /**
                 * 开始执行主函数
                 */
                var curr_res = this.processList[this.current_index - 1];
                if (typeof curr_res == undefined || curr_res == undefined) {
                    this.log("本流程无节点函数");
                    return;
                }
                return curr_res(res);
            } catch (e) {
                this.log("catch");
                this.log("流程异常, err:---------");
                this.log(e);
                return this.err_catch(e);
            }
        },
        /**
         * 开始流程，执行第一个方法
         */
        start: function(res) {
            this.process_start_data = res;
            this.log("current env:" + this.env);
            /**
             * 初始化启动参数
             */
            this.current_index = 1;
            this.timeBegin = new Date().getTime();
            // this.isRunning = true;
            this.set_state(true);
            this.sysTimeoutFunc = undefined;


            //开发模式下的日志打印
            this.log("return data is ---------");
            this.log(res);
            this.log("开始调用方法:" + this.processNameList[this.current_index - 1]);

            try {
                /**
                 * 判断是否需要预处理
                 */
                var pre_res = this.preList[this.current_index - 1];
                if (typeof pre_res != undefined && pre_res) {
                    res = pre_res(res);
                }
                /**
                 * 开始执行主函数
                 */
                var curr_res = this.processList[this.current_index - 1];
                if (typeof curr_res == undefined || curr_res == undefined) {
                    this.log("本流程无节点函数");
                    return;
                }
                return curr_res(res);
            } catch (e) {
                return this.err_catch(e);
            }
        },

        /**
         * finalize
         */
        finalize: function() {
            this.log("finally, process use time is" + (new Date - this.timeBegin));
            //清理定时任务
            if (typeof this.sysTimeoutFunc != undefined && this.sysTimeoutFunc != undefined) {
                clearTimeout(this.sysTimeoutFunc);
                this.sysTimeoutFunc = undefined;
            }

            //执行最终的数据清理函数
            if (typeof this.finalFunction != undefined && this.finalFunction != undefined) {
                this.finalFunction();
            }

            //判断是否为跳转操作
            if (typeof this.redirectTo_type != undefined && this.redirectTo_type != undefined) {
                this.log("结束流程页面跳转方式[" + this.redirectTo_type + "]跳转页面[" + this.redirectTo_url + "]");
                var pageTo = this.redirectTo_url;
                if (this.redirectTo_type == "reLaunch") {
                    this.redirectTo_type = undefined;
                    this.redirectTo_url = undefined;
                    my.reLaunch({
                        url: pageTo,
                    });
                }
                if (this.redirectTo_type == "redirectTo") {
                    this.redirectTo_type = undefined;
                    this.redirectTo_url = undefined;
                    my.redirectTo({
                        url: pageTo,
                    });
                }
                if (this.redirectTo_type == "navigateTo") {
                    this.redirectTo_type = undefined;
                    this.redirectTo_url = undefined;
                    my.navigateTo({
                        url: pageTo,
                    });
                }
                if (this.redirectTo_type == "navigateBack") {
                    this.redirectTo_type = undefined;
                    this.redirectTo_url = undefined;
                    my.navigateBack({
                        url: pageTo,
                    });
                }
            }
        },

        /**
         * 停止流程
         */
        stop: function() {
            if (!this.isRunning) {
                return false;
            }
            this.log("manually stop");
            this.set_state(false);
            this.finalize();
            return true;
        },
        /**
         * 执行下一个方法的函数
         */
        then: function(res) {
            try {
                if (typeof res != undefined && res != undefined) {
                    this.log("-----return data is:----------");
                    this.log(res);
                }

                /**
                 * 节点内的定时器清理
                 */
                if (this.sysTimeoutFunc != undefined) {
                    clearTimeout(this.sysTimeoutFunc);
                    this.sysTimeoutFunc = undefined;
                }


                /**
                 * 判断是否需要执行上一个方法的后处理函数
                 */
                var after_res = this.afterList[this.current_index - 1];
                if (typeof after_res != undefined && after_res) {
                    res = after_res(res);
                }
                /**
                 * 判断流程是否被停止
                 */
                if (!this.get_state()) {
                    this.log("when run then function, the process is stoped before");
                    return res;
                }

                // 获取下一个执行方法
                var nextFunction = this.processList[this.current_index];

                //下一个方法是否存在
                var isNextFunEmptyFlag = (typeof nextFunction == undefined || nextFunction == undefined);
                /**
                 * 判断是否超时
                 * 1. 如果没有定时任务，则不触发超时条件
                 * 2. 如果时间未过期， 则不触发超时条件
                 * 3. 如果是最后一个接口，则不触发超时条件
                 * 4. 反之，触发超时条件
                 */
                if (typeof this.timeFunction != undefined && this.timeFunction != undefined && new Date().getTime() - this.timeBegin > this.timeout && !isNextFunEmptyFlag) {
                    var time_res = this.timeFunction();
                    return time_res;
                }
                this.current_index = this.current_index + 1;


                /**
                 * 判断是否需要执行当前方法的预处理函数
                 */
                var pre_res = this.preList[this.current_index - 1];
                if (typeof pre_res != undefined && pre_res) {
                    res = pre_res(res);
                }

                /**
                 * 执行下一个方法
                 */
                this.log("-----call next node-----");
                if (isNextFunEmptyFlag) {
                    //下一个方法未定义，则直接结束
                    this.log("终极节点");
                    this.set_state(false);
                    this.finalize(); //执行最后的清理操作
                    return res;
                } else {
                    this.log("开始调用方法:" + this.processNameList[this.current_index - 1]);
                    return nextFunction(res);
                }
            } catch (err) {
                this.err_catch(err);
            }
        },
        /**
         * 节点跳转
         * @param {节点名称} nodeName 
         * @param {上一个节点的返回参数/下一个节点函数的入参} res 
         */
        jumpTo: function(nodeName, res) {
            try {
                if (typeof res != undefined && res != undefined) {
                    this.log("-----return data is:----------");
                    this.log(res);
                }
                this.log("call jumTo function, nextNode:" + nodeName);
                /**
                 * 节点内的定时器清理
                 */
                if (this.sysTimeoutFunc != undefined) {
                    clearTimeout(this.sysTimeoutFunc);
                    this.sysTimeoutFunc = undefined;
                }

                /**
                 * 判断流程是否被停止
                 */
                if (!this.get_state()) {
                    this.log("when run then function, the process is stoped before");
                    return res;
                }

                /**
                 * 判断是否需要执行上一个方法的后处理函数
                 */
                var after_res = this.afterList[this.current_index - 1];
                if (typeof after_res != undefined && after_res) {
                    res = after_res(res);
                }

                for (let i = 0; this.processNameList[i] != undefined; i++) {
                    if (nodeName == this.processNameList[i]) {
                        this.log("fit the nodeName, index:" + i);
                        this.current_index = i;
                    }
                }

                // 获取下一个执行方法
                var nextFunction = this.processList[this.current_index];

                //下一个方法是否存在
                var isNextFunEmptyFlag = (typeof nextFunction == undefined || nextFunction == undefined);
                /**
                 * 判断是否超时
                 * 1. 如果没有定时任务，则不触发超时条件
                 * 2. 如果时间未过期， 则不触发超时条件
                 * 3. 如果是最后一个接口，则不触发超时条件
                 * 4. 反之，触发超时条件
                 */
                if (typeof this.timeFunction != undefined && this.timeFunction != undefined && new Date().getTime() - this.timeBegin > this.timeout && !isNextFunEmptyFlag) {
                    var time_res = this.timeFunction();
                    return time_res;
                }
                this.current_index = this.current_index + 1;


                /**
                 * 判断是否需要执行当前方法的预处理函数
                 */
                var pre_res = this.preList[this.current_index - 1];
                if (typeof pre_res != undefined && pre_res) {
                    res = pre_res(res);
                }

                /**
                 * 执行下一个方法
                 */
                this.log("-----call next node-----");
                if (isNextFunEmptyFlag) {
                    //下一个方法未定义，则直接结束
                    this.log("终极节点");
                    this.set_state(false);
                    this.finalize(); //执行最后的清理操作
                    return res;
                } else {
                    this.log("开始调用方法:" + this.processNameList[this.current_index - 1]);
                    return nextFunction(res);
                }
            } catch (err) {
                this.err_catch(err);
            }
        },
        /**
         * 执行拒绝策略
         */
        reject: function(res) {
            this.log("call reject function, err data is:------------");
            this.log(res);
            if (!this.get_state()) {
                this.log("当前流程已结束");
                return;
            }
            this.set_state(false);
            this.finalize();
            this.log("触发" + this.processNameList[this.current_index - 1] + "拒绝策略");
            var fun = this.rejectList[this.current_index - 1];
            if (typeof fun == undefined || fun == undefined) {
                if (typeof this.errDefault == undefined || this.errDefault == undefined) {
                    return res;
                } else {
                    return this.errDefault(res);
                }
            } else {
                return fun(res);
            }
        },

        /**
         * reLaunch 页面跳转，同时结束流程
         */
        reLaunch: function(url) {
            this.redirectTo_type = "reLaunch";
            this.redirectTo_url = url;
            return;
        },
        /**
         * redirectTo 页面跳转，同时结束流程
         */
        redirectTo: function(url) {
            this.redirectTo_type = "redirectTo";
            this.redirectTo_url = url;
            return;
        },
        /**
         * navigateTo 页面跳转，同时结束流程
         */
        navigateTo: function(url) {
            this.redirectTo_type = "navigateTo";
            this.redirectTo_url = url;
            return;
        },
        /**
         * navigateBack 页面跳转，同时结束流程
         */
        navigateBack: function(url) {
            this.redirectTo_type = "navigateBack";
            this.redirectTo_url = url;
            return;
        },


        /**
         * 每个方法的预处理
         */
        pre: function() {
            return this;
        },

        /**
         * 每个方法的后处理
         */
        after: function() {
            return this;
        },
        /**
         * 当前方法抛出异常，执行异常处理方法
         */
        err_catch: function(res) {
            // if (!this.isRunning) {
            if (!this.get_state()) {
                return;
            }
            this.log("------" + this.processNameList[this.current_index] + "运行中发生错误");
            this.log(res);

            // this.isRunning = false;
            this.set_state(false);
            this.finalize();
            var errFunction = this.errList[this.current_index];
            if (typeof errFunction == undefined || errFunction == undefined) {
                if (typeof this.errDefault == undefined || this.errDefault == undefined) {
                    return;
                } else {
                    return this.errDefault(res);
                }
            } else {
                return errFunction(res);
            }
        },
        /**
         * 增加定时任务
         * @params timeFun : 超时触发的函数
         * @params tiemout : 超时时间（单位毫秒）
         *  */
        addTimer: function(timerFun, timeout) {
            this.timeFunction = timerFun
            this.timeout = timeout;
            return this;
        },

        /**
         * 获取剩余时间
         */
        getTimeoutTime(expectTime) {
            if (typeof this.timeBegin == undefined || this.timeBegin == undefined) {
                return 0;
            } else {
                var rsTime = this.timeout - (new Date().getTime() - this.timeBegin) > expectTime ? expectTime : this.timeout - (new Date().getTime() - this.timeBegin);
                return rsTime;
            }
        },
        /**
         * 调用系统的定时器，确保在一个节点函数中，也可以使用超时任务。
         * @param {定时任务} sysTimeFun 
         */
        setSysTimer: function(sysTimeFun) {
            if (this.sysTimeoutFunc != undefined) {
                clearTimeout(this.sysTimeoutFunc);
                this.sysTimeoutFunc = undefined;
            }
            this.sysTimeoutFunc = sysTimeFun;
        },
        /**
         * 增加延迟函数，用于测试使用
         * 例如：调试蓝牙的时候，如果测试连接连接蓝牙之后，发送数据的时候，蓝牙断开。
         * 则可以在连接设备函数和发送数据函数之间，增加延迟函数，使得测试人员有时间进行相应的操作
         */
        add_delay() {
            this.add(() => {
                setTimeout(() => {
                    this.then();
                }, 3000);
            }, "延迟3s函数");
            return this;
        }
    };
    //新建一个流程函数
    return process_info;
}

/**
 * 定义本页面，向外暴露的接口
 */
export default {
    create,
    addProcess,
    getProcess,
    addFilter,
    getFilter,
}